package demo.java.lang;

import org.junit.Test;

import java.util.Map;
import java.util.Properties;

public class SystemDemo {

    public static void main(String[] args) {
        System.out.println(System.currentTimeMillis());
    }

    /**
     * System.arraycopy() 方法。该方法被标记了native，调用了系统的C/C++代码，在JDK中是看不到的，但在openJDK中可以看到其源码。
     * 该函数实际上最终调用了C语言的memmove()函数，因此它可以保证同一个数组内元素的正确复制和移动，比一般的复制方法的实现效率要高很多，很适合用来批量处理数组。
     * Java强烈推荐在复制大量数组元素时用该方法，以取得更高的效率；
     */
    public void arraycopy() {
        Object[] src = null, dest = null;
        System.arraycopy(src, 0, dest, 0, 1);
    }

    /**
     * 在C++中，对象所占的内存在程序结束运行之前一直被占用，在明确释放之前不能分配给其它对象； 而在Java中，当没有对象引用指向原先分配给某个对象的内存时，该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。
     * 事实上，除了释放没用的对象，垃圾回收也可以清除内存记录碎片。由于创建对象和垃圾回收器释放丢弃对象所占的内存空间，内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端，JVM将整理出的内存分配给新的对象。
     * <p>
     * 调用System.gc()也仅仅是一个请求(建议)。JVM接受这个消息后，并不是立即做垃圾回收，而只是对几个垃圾回收算法做了加权，使垃圾回收操作容易发生，或提早发生，或回收较多而已
     * <p>
     * finalize()方法
     * <p>
     * 在JVM垃圾回收器收集一个对象之前，一般要求程序调用适当的方法释放资源，这个方法就是finalize（）。
     * 一旦垃圾回收器准备好释放对象占用的存储空间，首先会去调用finalize()方法进行一些必要的清理工作。之所以要使用finalize()，是存在着垃圾回收器不能处理的特殊情况。假定你的对象（并非使用new方法）获得了一块“特殊”的内存区域，由于垃圾回收器只知道那些显示地经由new分配的内存空间，所以它不知道该如何释放这块“特殊”的内存区域，那么这个时候java允许在类中override
     * Object这个类中的finalize()方法,自己动手去执行清理工作
     * <p>
     * 特殊的区域例如：1）由于在分配内存的时候可能采用了类似 C语言的做法，而非JAVA的通常new做法。这种情况主要发生在native method中，比如native
     * method调用了C/C++方法malloc()函数系列来分配存储空间，但是除非调用free()函数，否则这些内存空间将不会得到释放，那么这个时候就可能造成内存泄漏。但是由于free()方法是在C/C++中的函数，所以finalize()中可以用本地方法来调用它。以释放这些“特殊”的内存空间。2）又或者打开的文件资源，这些资源不属于垃圾回收器的回收范围。
     * <p>
     * 内存泄露：是指无用对象（不再使用的对象）持续占有内存或无用对象的内存得不到及时释放，从而造成的内存空间的浪费称为内存泄露。内存泄露有时不严重且不易察觉，这样开发者就不知道存在内存泄露，但有时也会很严重，会提示你Out of
     * memory。
     * <p>
     * Java内存泄露根本原因是什么呢？长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露.
     * <p>
     * java中内存泄露的发生场景。具体主要有如下几大类：
     *
     * <li>1、静态集合类引起内存泄露：像HashMap、Vector等的使用最容易出现内存泄露，这些静态变量的生命周期和应用程序一致，他们所引用的所有的对象Object也不能被释放，因为他们也将一直被Vector等引用着。
     * <li>2、当集合里面的对象属性被修改后，再调用remove（）方法时不起作用。
     * <li>3、
     * 监听器：编程中，我们都需要和监听器打交道，通常一个应用当中会用到很多监听器，我们会调用一个控件的诸如addXXXListener()等方法来增加监听器，但往往在释放对象的时候却没有记住去删除这些监听器，从而增加了内存泄漏的机会。
     * <li>4、各种连接
     * <p>
     * 比如数据库连接（dataSourse.getConnection()），网络连接(socket)和io连接，除非其显式的调用了其close（）方法将其连接关闭，否则是不会自动被GC 回收的。对于Resultset
     * 和Statement 对象可以不进行显式回收，但Connection 一定要显式回收，因为Connection 在任何时候都无法自动回收，而Connection一旦回收，Resultset 和Statement
     * 对象就会立即为NULL。 但是如果使用连接池，情况就不一样了，除了要显式地关闭连接，还必须显式地关闭Resultset Statement 对象（关闭其中一个，另外一个也会关闭），否则就会造成大量的Statement
     * 对象无法释放，从而引起内存泄漏。这种情况下一般都会在try里面去的连接，在finally里面释放连接。
     *
     * <li>5、内部类和外部模块等的引用.内部类的引用是比较容易遗忘的一种，而且一旦没释放可能导致一系列的后继类对象没有释放。
     *
     * <li>6、单例模式.不正确使用单例模式是引起内存泄露的一个常见问题，单例对象在被初始化后将在JVM的整个生命周期中存在（以静态变量的方式），如果单例对象持有外部对象的引用，那么这个外部对象将不能被jvm正常回收，导致内存泄露，
     */
    static void gc() {
        System.gc();
    }

    /**
     * 分代收集器(generializational
     * collector)将堆分为多个代。在年轻的代中创建对象，满足某些提升标准的对象，如经历了特定次数垃圾收集的对象，将被提升到下一更老的代。分代收集器对不同的代可以自由使用不同的收集策略，对各代分别进行垃圾收集。
     * <p>
     * 分代收集的一个优点是它不同时收集所有的代，因此可以使垃圾收集暂停更短。当分配器不能满足分配请求时，它首先触发一个 小的收集（minor collection），它只收集最年轻的代。
     * 因为年轻代中的许多对象已经死亡，复制收集器完全不用分析死亡的对象，所以小的收集的暂停可以相当短并通常可以回收大量的堆空间。如果小的收集释放了足够的堆空间，那么用户程序就可以立即恢复。
     * 如果它不能释放足够的堆空间，那么它就继续收集上一代，直到回收了足够的内存。（在垃圾收集器进行了全部收集以后仍不能回收足够的内存时，它将扩展堆或者抛出 OutOfMemoryError ）
     * <p>
     * 老对象和年轻对象,大多数对象是在年轻的时候死亡的,当大多数对象在年轻时死亡时，复制收集器可以执行得相当好，因为复制收集器完全不访问死亡的对象，它们只是将活的对象复制到另一个堆区域中，然后一次性收回所有的剩余空间。
     * 不过，复制收集器处理长寿对象却很糟糕，它要从一个半空间向另一个半空间反复来回复制这些对象。相反，标记-整理收集器对于长寿对象可以工作得很好，因为长寿对象趋向于沉在堆的底部，从而不用再复制。
     * 不过，标记-清除和标记-理整收集器要做很多额外的分析死亡对象的工作，因为在清除阶段它们必须分析堆中的每一个对象。
     */
    static void generationalGarbageCollection() {

    }

    static void demo() {
        System.getProperty("rocketmq.client.name", "DEFAULT");
        System.console();
    }

    /**
     * 获取环境变量。
     * <blockquote><pre>
     * 特性	System.getenv()	System.getProperty()
     * 来源	操作系统环境变量	JVM系统属性
     * 作用范围	整个操作系统	当前JVM实例
     * 持久性	长期存在	JVM运行期间
     * 设置方式	操作系统命令(set/export)	JVM参数(-D)、代码设置
     * 平台依赖性	高（不同OS不同）	低（Java标准）
     * 可变性	通常只读	可读写（运行时）
     * <pre/></blockquote>
     */
    @Test
    public void testGetEnv() {
        Map<String, String> env = System.getenv();
        env.forEach((k, v) -> System.out.println(k + "=" + v));

        String swimlanes = System.getenv("env.swimlanes");
        System.err.println(swimlanes);
    }

    /**
     * 获取系统属性
     */
    @Test
    public void testGetProperty() {
        Properties properties = System.getProperties();
        properties.forEach((k, v) -> System.out.println(k + "=" + v));

        String javaHome = System.getProperty("env.swimlanes");
        System.err.println(javaHome);
    }

}
